fix(cli): fix join dropping non-string x-* path extension properties#2949
Conversation
🦋 Changeset detectedLatest commit: 1fa9e74 The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Clarified the fix for join extension property to specify that it addresses non-string x-* path extension properties.
Performance Benchmark (Lower is Faster)
|
| .mockImplementationOnce(() => | ||
| Promise.resolve({ | ||
| source: { absoluteRef: 'ref-b' }, | ||
| parsed: anotherPathWithDifferentObjectExtension, |
There was a problem hiding this comment.
What if the object had different keys though? Like a.yaml has owner and b.yaml has team?
There was a problem hiding this comment.
A warning log is being output.
I think we'll just have to handle this the same way we do other standard items.
If this part overlaps, it means the paths also overlap.
There was a problem hiding this comment.
@nonchan7720 Please add a test for this case { owner: 'team-a' } and { team: 'x' }.
kanoru3101
left a comment
There was a problem hiding this comment.
Thanks for the contribution. Checked it out locally — works as expected, non-string x-* path extensions now merge the same way as regular path-level fields (first one wins, warning on conflict).
Left a few comments.
| .mockImplementationOnce(() => | ||
| Promise.resolve({ | ||
| source: { absoluteRef: 'ref-b' }, | ||
| parsed: anotherPathWithDifferentObjectExtension, |
There was a problem hiding this comment.
@nonchan7720 Please add a test for this case { owner: 'team-a' } and { team: 'x' }.
Co-authored-by: Viktor Sydor <31951646+kanoru3101@users.noreply.github.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 310638c. Configure here.
RomanHotsiy
left a comment
There was a problem hiding this comment.
LGTM, left one simplification comment
| if (typeof pathItem[field] === 'string') { | ||
| if ( | ||
| typeof pathItem[field] === 'string' || | ||
| (field.startsWith('x-') && typeof pathItem[field] !== 'string') |
There was a problem hiding this comment.
| (field.startsWith('x-') && typeof pathItem[field] !== 'string') | |
| (field.startsWith('x-')) |
Co-authored-by: Viktor Sydor <31951646+kanoru3101@users.noreply.github.com>
|
What else do I need to do to get this PR merged? 🙏 |
|
Hey @nonchan7720 |

What/Why/How?
Fixes
joinsilently dropping non-stringx-*extension properties defined directly under a path item (e.g.paths./pets/{petId}.x-foo: true).collectPathsonly merged path-level extensions when their value was a string, viacollectPathStringFields. Non-string values(booleans, objects, arrays, numbers) were never copied into the joined document.
collectPathExtensionnow handles every non-stringx-*field on a path item: it copies the value into the joined path the firsttime it's seen, and logs a warning instead of silently overwriting when two source documents provide different values for the same
field.
Reference
Fixes #1574
Testing
Added a
path extensionstest group tojoin.test.tswith fixtures indocuments.tscovering:x-*path extension when both source documents agree on the valueVerified against the pre-fix implementation that both new tests fail without this change.
Screenshots (optional)
N/A — CLI behavior change only.
Check yourself
packages/clionlynpx changesetbefore merging (@redocly/cli, patch)Security
input surface
Note
Low Risk
Scoped CLI merge logic fix with tests; no new input surface beyond existing parsed OpenAPI documents.
Overview
Fixes
joinsilently dropping path-levelx-*extensions when values are not strings (objects, booleans, arrays, etc.).In
collect-paths.ts, path item fields are now merged when the value is a string or the key starts withx-, so those extensions are copied into the joined document like string fields (summary,description). Conflict detection usesdequalinstead of!==, so object extensions with the same content merge without a warning; differing values keep the first document’s value and emitlogger.warn.Adds a
path extensionstest group and fixtures for matching objectx-metadata, conflicting values, and objects with different keys. Includes a patch changeset for@redocly/cli.Reviewed by Cursor Bugbot for commit 1fa9e74. Bugbot is set up for automated code reviews on this repo. Configure here.